package com.zkt.practice.server.config.redis;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @author 赵开泰
 * @program jc-club
 * @date 2025/3/23
 * @description RedisUtil工具类
 **/

@Component
@Slf4j
public class RedisUtil {
	
	@Resource
	private RedisTemplate<String, Object> redisTemplate;
	
	@Resource
	private ObjectMapper objectMapper;
	
	private static final String CACHE_KEY_SEPARATOR = ":";
	
	/**
	 * 构建缓存key
	 *
	 * @param strObjs key中包含的字符串
	 * @return 拼接好的key
	 */
	public String buildKey(String... strObjs) {
		return String.join(CACHE_KEY_SEPARATOR, strObjs);
	}
	
	/**
	 * 判断是否存在key
	 *
	 * @param key key
	 * @return 是否存在
	 */
	public boolean exist(String key) {
		return redisTemplate.hasKey(key);
	}
	
	/**
	 * 删除key
	 *
	 * @param key key
	 * @return 是否成功
	 */
	public boolean del(String key) {
		return redisTemplate.delete(key);
	}
	
	/**
	 * 存入key-value，不会过期
	 *
	 * @param key   key
	 * @param value value
	 */
	public void set(String key, Object value) {
		redisTemplate.opsForValue().set(key, value);
	}
	
	/**
	 * 存入key-value，指定存在时长
	 *
	 * @param key      key
	 * @param value    value
	 * @param time     时长
	 * @param timeUnit 时长单位
	 * @return 是否成功
	 */
	public boolean setNx(String key, Object value, long time, TimeUnit timeUnit) {
		return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key, value, time, timeUnit));
	}
	
	/**
	 * 获取对象类型缓存
	 *
	 * @param key key
	 * @return 缓存的值
	 */
	public <T> T get(String key) {
		return objectMapper.convertValue(redisTemplate.opsForValue().get(key), new TypeReference<>() {
		});
	}
	
	/**
	 * 获取存储的是序列化字符串的对象类型缓存
	 *
	 * @param key key
	 * @return 缓存的值
	 */
	@SneakyThrows
	public <T> T get(String key, Class<T> clazz) {
		String objectString = this.get(key);
		return objectMapper.readValue(objectString, clazz);
	}
	
	/**
	 * 获取列表类型缓存
	 *
	 * @param key key
	 * @return 缓存的值
	 */
	@SneakyThrows
	public <T> List<T> getList(String key, Class<T> clazz) {
		String objectString = this.get(key);
		JavaType javaType = objectMapper.getTypeFactory().constructCollectionType(List.class, clazz);
		return objectMapper.readValue(objectString, javaType);
	}
	
	public Boolean zAdd(String key, String value, Long score) {
		return (redisTemplate.opsForZSet().add(key, value, score));
	}
	
	public Long countZset(String key) {
		return redisTemplate.opsForZSet().size(key);
	}
	
	public Set<Object> rangeZset(String key, long start, long end) {
		return redisTemplate.opsForZSet().range(key, start, end);
	}
	
	public Long removeZset(String key, Object value) {
		return redisTemplate.opsForZSet().remove(key, value);
	}
	
	public void removeZsetList(String key, Set<String> values) {
		values.forEach(value -> redisTemplate.opsForZSet().remove(key, value));
	}
	
	public Double score(String key, Object value) {
		return redisTemplate.opsForZSet().score(key, value);
	}
	
	public Set<Object> rangeByScore(String key, long start, long end) {
		return redisTemplate.opsForZSet().rangeByScore(key, start, end);
	}
	
	public Object addScore(String key, Object value, double score) {
		return redisTemplate.opsForZSet().add(key, value, score);
	}
	
	public Object rank(String key, Object value) {
		return redisTemplate.opsForZSet().rank(key, value);
	}
	
}